﻿using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Caching.Memory;
using System.Net;
using System.Security.Claims;

namespace IdentityWebApi
{
    public class JWTValidationFilter : IAsyncActionFilter
    {
        private readonly IMemoryCache _memoryCache;
        private readonly UserManager<User> _userManager;

        public JWTValidationFilter(IMemoryCache memoryCache,UserManager<User> userManager)
        {
            _memoryCache = memoryCache;
            _userManager = userManager;
        }
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            var claimUserId = context.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier);
            // 对于登录接口直接跳过
            if (claimUserId == null)
            {
                await next();
                return;
            }
            long userId = long.Parse(claimUserId.Value);
            string cacheKey = $"JWTValidationFilter.UserInfo.{userId}";
            User user = await _memoryCache.GetOrCreateAsync(cacheKey, async e =>
            {
                e.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(5);
                return await _userManager.FindByIdAsync(userId.ToString());
            });
            if(user == null)
            {
                var result = new ObjectResult($"UserId:{userId} not found");
                result.StatusCode = (int)HttpStatusCode.Unauthorized;
                return;
            }
            var claimVersion = context.HttpContext.User.FindFirst(ClaimTypes.Version);
            long jwtVersionOfReq = long.Parse(claimVersion!.Value);
            if (jwtVersionOfReq >= user.JwtVersion)
            {
                await next();
            }
            else
            {
                var result = new ObjectResult("JwtVersion missmatch");
                result.StatusCode = (int)HttpStatusCode.Unauthorized;
                context.Result = result;
                return;
            }
        }
    }
}
